package test.progenies.ecg.asm31.methods;

import static org.junit.Assert.assertNotNull;

import org.junit.Before;

import com.progenies.ecg.generator.ClassGenerator;
import com.progenies.ecg.generator.ClassGeneratorFactory;
import com.progenies.ecg.model.ClassObject;
import com.progenies.ecg.model.ConstructorObject;
import com.progenies.ecg.model.codeparts.lines.LineFactory;

public abstract class BaseTestInternalStaticMethods {

	protected ClassGenerator clsGenerator;
	private static int counter = 0;

	@Before
	public void setUp() throws Exception {
		clsGenerator=ClassGeneratorFactory.getClassGenerator();
		assertNotNull(clsGenerator);
	}

	public ClassObject createClass() {
			counter++;
			int index=counter;
			LineFactory lineFactory=clsGenerator.lineFactory;
			String subpackage=this.getClass().getPackage().getName().substring(this.getClass().getPackage().getName().lastIndexOf('.')+1);
			ClassObject cls=clsGenerator.objectFactory.classes.createClass("test."+subpackage+".InternalStaticMethodTestClass"+index);
			cls.setSuperClass(MethodClass.class);
			
	//		//creates static final field
	//		FieldObject<Long> fld=clsGenerator.objectFactory.fields.createField("staticField", long.class);
	//		fld.setModifiers(new int[] {Opcodes.ACC_PROTECTED, Opcodes.ACC_STATIC, Opcodes.ACC_FINAL});
	//		fld.setValue(88l);
	//		cls.getFields().add(fld);
	//		
	//		//creates instance final field
	//		FieldObject<Long> fld2=clsGenerator.objectFactory.fields.createField("instanceField", long.class);
	//		fld2.setModifiers(new int[] {Opcodes.ACC_PROTECTED, Opcodes.ACC_FINAL});
	//		fld2.setValue(56l);
	//		cls.getFields().add(fld2);
			
			//override default constructor
			ConstructorObject consObject=clsGenerator.objectFactory.constructors.createConstructor();
			consObject.setCode(lineFactory.methods.invokeSuperConstructor());
			cls.getConstructors().add(consObject);
			
	//		//instance method
	//		MethodObject mth=clsGenerator.objectFactory.methods.createMethod("instanceMethod");
	//		mth.setReturnType(long.class);
	//		mth.setCode(clsGenerator.lineFactory.methods.returnStaticValue(5l));
	//		cls.getMethods().add(mth);
	//		
	//		//static method
	//		MethodObject mthSt=clsGenerator.objectFactory.methods.createMethod("staticMethod");
	//		mthSt.setReturnType(long.class);
	//		mthSt.setModifiers(new int[] {Opcodes.ACC_STATIC, Opcodes.ACC_PRIVATE});
	//		mthSt.setCode(clsGenerator.lineFactory.methods.returnStaticValue(9l));
	//		cls.getMethods().add(mthSt);
					
			return cls;
		}

	public static class MethodClass
	{
		static int value;
		
		protected int value2;
		
		public static int methodCheck()
		{
			return value;
		}
		
		public static void testVoid()
		{
			value++;
			return;
		}
		
		public static int testInt()
		{
			return 5;
		}
		
		public static double testDouble()
		{
			return 7d;
		}
		
		public static ValueObject testValueObject(int params[])
		{
			if(params==null)
				return null;
			
			int tmp=0;
			for(int i=0;i<params.length;i++)
			{
				tmp+=params[i];
			}
			return testValueObject(tmp);
		}
		
		public static ValueObject testValueObject(ValueObject params[])
		{
			if(params==null)
				return null;
			
			int tmp=0;
			for(int i=0;i<params.length;i++)
			{
				tmp+=params[i].internalValue;
			}
			return testValueObject(tmp);
		}
		
		public static ValueObject testValueObject(int param)
		{
			value=0;
			return param>0?new ValueObject(param):null;
		}
		
		public static ExtendedValueObject testExtendedValueObject(int param)
		{
			return param>0?new ExtendedValueObject(param):null;
		}
		
		public static ValueIface testIfaceValueObject(int param)
		{
			return param>0?new ValueObject(param):null;
		}
		
		public static void setValueObject(ValueObject param)
		{
			value=param.getInternalValue();
		}
		
		
	}
	
	public interface ValueIface
	{
		public int getInternalValue();
	}
	
	public static class ValueObject implements ValueIface
	{
		public int internalValue;
		
		public ValueObject(int v)
		{
			this.internalValue=v;
		}
		
		
		public int getInternalValue()
		{
			return internalValue;
		}
	}
	
	public static class ExtendedValueObject extends ValueObject
	{
		public ExtendedValueObject(int val)
		{
			super(val*2);
		}
	}

}
